package com.atguigu.day1;

import java.util.concurrent.TimeUnit;

/**
 * synchronized,java的锁，到底锁的是什么
 *  一锁八情况
 *  1.标准访问，请问先打印邮件还是短信？ 邮件
 *  2.邮件暂停1秒，请问现打印邮件还是短信？ 邮件
 *  3.新增普通hello方法，先打印邮件还是hello？ hello
 *  4.有两部手机，请问先打印邮件还是短信？ 短信
 *  5.静态同步方法，同一部手机，请问先打印邮件还是手机？邮件
 *  6.静态同步方法，有两部手机，请问先打印邮件还是手机？邮件
 *  7.一个普通同步方法，一个静态同步方法，一部手机，请问先打印邮件还是先打印短信？短信
 *  8.一个普通同步方法，一个静态同步方法，两部手机，请问先打印邮件还是短信？短信
 *
 *
 *  1-2：一个对象里面如果有多个synchronized方法，某一个时刻内，只要一个线程去调用其中的一个synchronized方法了，
 *      其它线程对象都只能等待，换句话说，某一个时刻内，只能有唯一一个线程去访问这些synchronized方法
 *      锁的是当前对象this，被锁定后，其它的线程都不能进入到当前对象的其它的synchronized方法
 *
 *  3-4：加个普通方法后发现和同步锁无关，被锁定后，其他的线程都不能进入到当前对象的其他的synchronized方法
 *      换成两个对象后，不是同一把锁了，情况立刻变化
 *
 *  5-6：都换成静态同步方法后情况又变化
 *       若是普通同步方法，new   this，具体的一部手机，所有的普通同步方法用的都是同一把锁——实例对象本身
 *       若是静态同步方法，static  Class，锁的是唯一的一个模板
 *  7-8：当一个线程试图访问同步代码时它首先必须得到锁，退出或抛出异常时必须释放锁。
 *
 *      所有的普通同步方法用的都是同一把锁——实例对象本身，，就是new出来的具体实例对象本身
 *      也就是说如果一个实例对象的普通同步方法获取锁后，该实例对象的其他普通同步方法必须等待获取锁的方法释放锁后才能获取锁，
 *      可是别的实例对象的普通同步方法因为跟该实例对象的普通同步方法用的是不同的锁，所以不用等待该实例对象已获取锁的普通
 *      同步方法释放锁就可以获取他们自己的锁。
 *
 *      所有的静态同步方法用的也是同一把锁——类对象本身，就是我们说过的唯一模板Class
 *      具体实例对象this和唯一模板Class，这两把锁是两个不同的对象，所以静态同步方法与普通同步方法之间是不会有竞态条件的。
 *      但是一旦一个静态同步方法获取锁后，其他的静态同步方法都必须等待该方法释放锁后才能获取锁
 *
 */


class Phone{
    public static synchronized void eamil(){
        try {
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
        System.out.println("---------eamil");
    }

    public  synchronized void sms(){
        System.out.println("---------sms");
    }
}

public class Lock8 {
    public static void main(String[] args) {
        Phone phone1 = new Phone();
        Phone phone2 = new Phone();
        //线程A发邮件
        new Thread(() ->{
            phone1.eamil();
        },"A").start();

        //暂停100毫秒，保证A线程先执行
        try {
            TimeUnit.MILLISECONDS.sleep(100);
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        //线程B发短信
        new Thread(() ->{
            //phone1.sms();
            phone2.sms();
        },"B").start();
    }
}


